use std::os::raw::c_void;

use ash::vk;
use ash::vk::DescriptorImageInfo;

use crate::VK_LOGP;
use crate::vulkan::vk_context;
use crate::vulkan::vk_utils::utils_info;
use crate::vulkan::vk_utils::utils_memory;
use crate::{vulkan::VkContext, VK_CHECK_UNSAFE};

use super::VkBuffer;
use super::VkMappedBuffer;
use super::{VkImage, VkTexture};

impl VkBuffer {
    /// Handler -> Memory
    /// 详情看VkImage::new的注释
    pub fn new(vk_context: &VkContext, 
        size: u64, 
        usage: vk::BufferUsageFlags, 
        sharing_mode: vk::SharingMode, 
        required_membits: &vk::MemoryPropertyFlags, data_to_trans: Option<*const c_void>) -> Self {
        // 创建Handler
        let mut buffer_ci = utils_info::get_buffer_create_info();
        buffer_ci.size              = size;
        buffer_ci.usage             = usage;
        buffer_ci.sharing_mode      = sharing_mode;
        let buffer_handler = match VK_CHECK_UNSAFE!(vk_context.vk_device.create_buffer(&buffer_ci, None)) {
            Some(inner_value)       => inner_value,
            None                    => VK_LOGP!("Failed to create_buffer")
        };
        // 分配内存
        let buffer_memory_requirements = unsafe{ vk_context.vk_device.get_buffer_memory_requirements(buffer_handler) };
        let mut memory_ai = utils_info::get_memory_allocate_info();
        memory_ai.allocation_size       = buffer_memory_requirements.size;
        memory_ai.memory_type_index     = utils_memory::find_memory_type(vk_context, required_membits, buffer_memory_requirements.memory_type_bits);       
        let buffer_memory = match VK_CHECK_UNSAFE!(vk_context.vk_device.allocate_memory(&memory_ai, None)) {
            Some(inner_value)   => inner_value,
            None                => VK_LOGP!("Failed to allocate_memory")
        };
        match VK_CHECK_UNSAFE!(vk_context.vk_device.bind_buffer_memory(buffer_handler, buffer_memory, 0)) {
            Some(_)             => (),
            None                => VK_LOGP!("Failed to bind_buffer_memory")
        };
        // 传输内存
        if let Some(cpu_data) = data_to_trans {
            let mapped_handler = match VK_CHECK_UNSAFE!(vk_context.vk_device.map_memory(buffer_memory, 0, size, vk::MemoryMapFlags::empty())) {
                Some(inner_value)   => inner_value as *mut c_void,
                None                => VK_LOGP!("Failed to map_memory")
            };
            unsafe{ 
                mapped_handler.copy_from_nonoverlapping(cpu_data, size as usize); 
                vk_context.vk_device.unmap_memory(buffer_memory);
            }
        }

        Self {
            handler         : buffer_handler,
            memory          : buffer_memory
        }
    }
}

impl<T> VkMappedBuffer<T> {
    pub fn new(vk_context: &VkContext, 
        size: u64, 
        usage: vk::BufferUsageFlags, 
        sharing_mode: vk::SharingMode, 
        required_membits: &vk::MemoryPropertyFlags, data_to_trans: Option<*const c_void>) -> Self {
        // 新建一个Buffer
        let buffer = VkBuffer::new(vk_context, size, usage, sharing_mode, required_membits, data_to_trans);
        // 对这份Buffer保存CPU侧Map出来的内存
        let mapped_handler = match VK_CHECK_UNSAFE!(vk_context.vk_device.map_memory(buffer.memory, 0, size, vk::MemoryMapFlags::empty())) {
            Some(inner_value)   => inner_value as *mut T,
            None                => VK_LOGP!("Failed to map_memory")
        };

        Self {
            buffer              : buffer,
            mapped_handler      : Some(mapped_handler)
        }
    }
}

impl VkImage {
    /// Vulkan新开内存的方式比较类似
    /// 1. 申请一个Handler，这个时候还没有创建内存，但是我们给了这个Handler需要的内存信息
    /// 2. 利用Handler去向Handler申请一块内存空间，这个就比较像malloc
    /// 3. 有了内存空间，我们还需要知道怎么"看待"这块空间，就需要构造一个View去看他，比较像(int*)malloc，就说我们用int的角度去看这块内存
    /// 所以是 Handler -> Memory -> View 
    /// 
    /// 顺序执行流程如下
    /// ```
    /// vkCreateXXXXX()
    /// vkGetXXXXXMemoryRequirements()
    /// vkAllocateMemory()
    /// vkBindXXXXXMemory()
    /// vkCreateXXXXXView()
    /// ```
    pub fn new(vk_context: &VkContext, 
        width: u32, 
        height: u32, 
        image_format: &vk::Format, 
        usage: vk::ImageUsageFlags,
        required_membits: &vk::MemoryPropertyFlags,
        aspect: vk::ImageAspectFlags) -> Self {
        // Step 1
        let mut image_ci = utils_info::get_image_create_info();
        image_ci.image_type     = vk::ImageType::TYPE_2D;
        image_ci.format         = *image_format;
        image_ci.extent         = vk::Extent3D {width: width, height: height, depth: 1};
        image_ci.mip_levels     = 1;
        image_ci.array_layers   = 1;
        image_ci.samples        = vk::SampleCountFlags::TYPE_1;
        image_ci.sharing_mode   = vk::SharingMode::EXCLUSIVE;
        image_ci.usage          = usage;
        image_ci.initial_layout = vk::ImageLayout::UNDEFINED;
        let image_handler = match VK_CHECK_UNSAFE!(vk_context.vk_device.create_image(&image_ci, None)) {
            Some(inner_value)   => inner_value,
            None                => VK_LOGP!("Failed to create_image")
        };

        // Step 2
        let image_memory_requirements  = unsafe{ vk_context.vk_device.get_image_memory_requirements(image_handler) };
        let mut memory_ai = utils_info::get_memory_allocate_info();
        memory_ai.allocation_size       = image_memory_requirements.size;
        memory_ai.memory_type_index     = utils_memory::find_memory_type(vk_context, required_membits, image_memory_requirements.memory_type_bits);
        let image_memory = match VK_CHECK_UNSAFE!(vk_context.vk_device.allocate_memory(&memory_ai, None)) {
            Some(inner_value)   => inner_value,
            None                => VK_LOGP!("Failed to allocate_memory")
        };
        match VK_CHECK_UNSAFE!(vk_context.vk_device.bind_image_memory(image_handler, image_memory, 0)) {
            Some(_)             => (),
            None                => VK_LOGP!("Failed to bind_image_memory")
        };

        // Step 3
        let image_view = vk_context.create_image_view_2d(&image_handler, image_format, &aspect);

        Self {
            handler     : image_handler,
            view        : image_view,
            memory      : image_memory,
            format      : image_format.clone()
        }
    }

    /// 释放资源
    pub fn destory_resources(&self, vk_context: &VkContext) {
        unsafe {
            vk_context.vk_device.destroy_image_view(self.view, None);
            vk_context.vk_device.free_memory(self.memory, None);
            vk_context.vk_device.destroy_image(self.handler, None);
        }
    }
}

impl VkTexture {
    /// 从Image构建一个Texture
    pub fn new(vk_context: &VkContext,
        vk_image            : &VkImage,
        vk_image_layout     : vk::ImageLayout
    ) -> Self {
        let sampler = vk_context.create_sampler();

        Self {
            handler     : vk_image.handler,
            memory      : vk_image.memory,
            format      : vk_image.format,
            description : vk::DescriptorImageInfo {
                sampler         : sampler,
                image_view      : vk_image.view,
                image_layout    : vk_image_layout
            }
        }
    }
    
    /// 释放资源
    pub fn destory_resources(&self, vk_context: &VkContext) {
        unsafe {
            vk_context.vk_device.destroy_image_view(self.description.image_view, None);
            vk_context.vk_device.free_memory(self.memory, None);
            vk_context.vk_device.destroy_image(self.handler, None);
            vk_context.vk_device.destroy_sampler(self.description.sampler, None);
        }
    }
}

// impl Default for VkTexture {
//     fn default() -> Self {
//         Self {
//             handler     : vk::Image::null(),
//             memory      : vk::DeviceMemory::null(),
//             description : DescriptorImageInfo::default(),
//             format      : vk::Format::default()
//         }
//     }
// }